/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package it.polimi.meteoCal.entity;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;

import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.validation.constraints.NotNull;
import org.primefaces.model.ScheduleEvent;

/**
 *
 * @author Michele
 */
@Entity(name = "EVENT")

public class Event implements ScheduleEvent, Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private String id;

    @NotNull(message = "May not be empty")
    private String title;

    @NotNull(message = "May not be empty")
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "START_DATETIME")
    private Date startDate;

    @NotNull(message = "May not be empty")
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "END_DATETIME")
    private Date endDate;

    @NotNull(message = "May not be empty")
    private boolean allDay;

    @NotNull(message = "May not be empty")
    private String place;

    @NotNull(message = "May not be empty")
    private boolean isOutdoor;

    private String styleClass;

    @NotNull(message = "May not be empty")
    private Boolean isPublic;

    @NotNull
    private Boolean isEditable;

    private String description;

    private String weatherSpescs;

    @OneToMany(cascade = CascadeType.ALL, targetEntity = WeatherForecast.class, mappedBy = "event", orphanRemoval = true)
    private List<WeatherForecast> weatherForecastList;

    @OneToOne(cascade = CascadeType.ALL)
    private BadWeather badWeatherSpecification;

    @ManyToOne()
    private Users createdBy;

    @ManyToMany()
    @JoinTable(name = "PARTICIPATION")
    private List<Calendar> goingUsers;

    @OneToMany(cascade = CascadeType.ALL, targetEntity = Request.class, mappedBy = "event", orphanRemoval = true)
    private List<Request> requestsList;

    @OneToMany(cascade = CascadeType.ALL, targetEntity = BadWeatherNotification.class, mappedBy = "event", orphanRemoval = true)
    private List<Request> badWeatherNotificationsList;

    /**
     * Constructor method
     */
    public Event() {
        isEditable = false;
        this.badWeatherSpecification = new BadWeather();
    }

    /**
     * Constructor method
     *
     * @param title: the event's title
     * @param start: the start datetime
     * @param end: the end datetime
     */
    public Event(String title, Date start, Date end) {
        this();
        setTitle(title);
        setStartDate(start);
        setEndDate(end);
    }

    /**
     *
     * @return the event's id
     */
    @Override
    public String getId() {
        return id;
    }

    /**
     *
     * @param id: the event's id
     */
    @Override
    public void setId(String id) {
        this.id = id;
    }

    /**
     *
     * @return the event's title
     */
    @Override
    public String getTitle() {
        return title;
    }

    /**
     *
     * @param title: the event's title
     */
    public void setTitle(String title) {
        this.title = title;
    }

    /**
     *
     * @return the start datetime of the event
     */
    @Override
    public Date getStartDate() {
        // startDate.setTime(startTime.getTime()); NON FUNZIONA!! TODO
        return startDate;
    }

    /**
     *
     * @param startDate: the start datetime of the event
     */
    public void setStartDate(Date startDate) {
        this.startDate = startDate;
    }

    /**
     *
     * @return the end datetime of the event
     */
    @Override
    public Date getEndDate() {
        // endDate.setTime(endTime.getTime()); NON FUNZIONA!! TODO
        return endDate;
    }

    /**
     *
     * @param endDate: the end datetime of the event
     */
    public void setEndDate(Date endDate) {
        this.endDate = endDate;
    }

    /**
     *
     * @return true if an event is tagged as all day, false otherwise
     */
    @Override
    public boolean isAllDay() {
        return allDay;
    }

    /**
     *
     * @param allDay: the all day flag of the event
     */
    public void setAllDay(boolean allDay) {
        this.allDay = allDay;
    }

    public String getWeatherSpescs() {
        return weatherSpescs;
    }

    public void setWeatherSpescs(String weatherSpescs) {
        this.weatherSpescs = weatherSpescs;
    }

    /**
     *
     * @return the place where the event is hold
     */
    public String getPlace() {
        return place;
    }

    /**
     *
     * @param place: the place where the event is hold
     */
    public void setPlace(String place) {
        this.place = place;
    }

    public boolean isIsOutdoor() {
        return isOutdoor;
    }

    public void setIsOutdoor(boolean isOutdoor) {
        this.isOutdoor = isOutdoor;
    }

    /**
     *
     * @param styleClass: the style of the event
     */
    public void setStyleClass(String styleClass) {
        this.styleClass = styleClass;
    }

    /**
     *
     * @return the style of the event
     */
    @Override
    public String getStyleClass() {
        return styleClass;
    }

    /**
     * Method not implemented by MeteoCal event entity, just to match the
     * interface
     *
     * @return null
     */
    @Override
    public Object getData() {
        return null;
    }

    /**
     * Method not implemented
     *
     * @param data
     */
    public void setData(Object data) {
    }

    public Boolean getIsPublic() {
        return isPublic;
    }

    public void setIsPublic(Boolean isPublic) {
        this.isPublic = isPublic;
    }

    /**
     *
     * @return true if the event is editable in the calendar, false otherwise
     */
    @Override
    public boolean isEditable() {
        return isEditable;
    }

    /**
     *
     * @param isEditable: the editable setting of the event
     */
    public void setEditable(Boolean isEditable) {
        this.isEditable = isEditable;
    }

    /**
     *
     * @return the event's description
     */
    @Override
    public String getDescription() {
        return description;
    }

    /**
     *
     * @param description the event's description
     */
    public void setDescription(String description) {
        this.description = description;
    }

    /**
     *
     * @return the event's weather forecast
     */
    public List<WeatherForecast> getWeatherForecastList() {
        if (weatherForecastList == null) {
            this.weatherForecastList = new ArrayList<>();
        }
        return weatherForecastList;
    }

    /**
     *
     * @param weatherForecast the event's weather forecast
     */
    public void setWeatherForecastList(List<WeatherForecast> weatherForecast) {
        this.weatherForecastList = weatherForecast;
    }

    /**
     *
     * @return the event's bad wethaer specification specified by the creator
     */
    public BadWeather getBadWeatherSpecification() {
        return badWeatherSpecification;
    }

    /**
     *
     * @param badWeatherSpecification the event's bad wethaer specification
     * specified by the creator
     */
    public void setBadWeatherSpecification(BadWeather badWeatherSpecification) {
        this.badWeatherSpecification = badWeatherSpecification;
    }

    /**
     *
     * @return the creator of the event
     */
    public Users getCreatedBy() {
        return createdBy;
    }

    /**
     *
     * @param createdBy the creator of the event
     */
    public void setCreatedBy(Users createdBy) {
        this.createdBy = createdBy;
    }

    /**
     *
     * @return a list with user's calendar that participate to the event
     */
    public List<Calendar> getGoingUsers() {
        return goingUsers;
    }

    /**
     *
     * @param goingUsers a list with user's calendar that participate to the
     * event
     */
    public void setGoingUsers(List<Calendar> goingUsers) {
        this.goingUsers = goingUsers;
    }

    /**
     * Method to add a going user to this event
     *
     * @param calendar the user's calendar to be added to participants
     */
    public void addGoingUser(Calendar calendar) {
        if (goingUsers == null) {
            goingUsers = new ArrayList<>();
        }
        goingUsers.add(calendar);
        if (!calendar.getGoingEvents().contains(this)) {
            calendar.addEvent(this);
        }
    }

    /**
     * Method to remove a going user to this event
     *
     * @param calendar the user's calendar to be removed from participants
     */
    public void removeGoingUser(Calendar calendar) {
        goingUsers.remove(calendar);
        if (calendar.getGoingEvents().contains(this)) {
            calendar.removeEvent(this);
        }
    }

    @Override

    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Event other = (Event) obj;
        if ((this.getTitle() == null) ? (other.getTitle() != null) : !this.getTitle().equals(other.getTitle())) {
            return false;
        }
        if (this.getStartDate() != other.getStartDate() && (this.getStartDate() == null || !this.getStartDate().equals(other.getStartDate()))) {
            return false;
        }
        if (this.getEndDate() != other.getEndDate() && (this.getEndDate() == null || !this.getEndDate().equals(other.getEndDate()))) {
            return false;
        }
        return true;
    }

    @Override

    public int hashCode() {
        int hash = 5;
        hash = 61 * hash + (this.getTitle() != null ? this.getTitle().hashCode() : 0);
        hash = 61 * hash + (this.getStartDate() != null ? this.getStartDate().hashCode() : 0);
        hash = 61 * hash + (this.getEndDate() != null ? this.getEndDate().hashCode() : 0);
        return hash;
    }

    @Override

    public String toString() {
        return "Event{title=" + getTitle() + ",startDate=" + getStartDate() + ",endDate=" + getEndDate() + "}";
    }

}
